import sys
import tkinter as tk
from PIL import Image

from config import AppConstants
from processors.brightness_contrast import BrightnessContrastProcessor
from processors.rotate import RotateProcessor
from processors.mirror import MirrorProcessor
from processors.resize import ResizeProcessor
from processors.crop import CropProcessor
from processors.grayscale import GrayscaleProcessor
from processors.equalize import EqualizeProcessor
from processors.subtract import SubtractProcessor
from processors.gamma import GammaProcessor
from processors.smoothing import SmoothingProcessor
from processors.morphology import MorphologyProcessor
from processors.cell_count import CellCountProcessor
from ui import ImageProcessorUI
from utils import open_image_file_dialog, save_image_file_dialog

class ImageProcessorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("图像处理工具")
        # 初始化窗口尺寸和位置
        self._setup_window_geometry()
        # 绑定窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        # 图像变量
        self.original_image = None  # 原始图像（原分辨率）
        self.current_image = None   # 当前处理状态（原分辨率）
        self.preview_image = None   # 预览用图像（固定分辨率）
        # 设置退出时的清理标志
        self.is_closing = False
        # 撤销参数
        self.image_history = []  # 图像历史栈（用于撤销）
        self.max_undo_steps = 10  # 最大撤销步数
        # 计算各区域高度
        self.window_height = self.root.winfo_screenheight()
        self.PREVIEW_TOP_AREA_HEIGHT = int(self.window_height * AppConstants.PREVIEW_AREA_RATIO)
        self.PREVIEW_HEIGHT = int(self.PREVIEW_TOP_AREA_HEIGHT * AppConstants.PREVIEW_IMAGE_RATIO)
        self.CONTROL_PANEL_HEIGHT = int(self.window_height * AppConstants.CONTROL_PANEL_RATIO)
        self.BUTTON_PANEL_HEIGHT = int(self.window_height * AppConstants.BUTTON_PANEL_RATIO)
        # 初始化UI
        self.ui = ImageProcessorUI(root)
        self.ui.setup_ui(self)
        # 初始化图像处理器
        self.processors = {
            "BrightnessContrast": BrightnessContrastProcessor(),
            "Rotate": RotateProcessor(),
            "Mirror": MirrorProcessor(),
            "Resize": ResizeProcessor(),
            "Crop": CropProcessor(),
            "Grayscale": GrayscaleProcessor(),
            "Equalize": EqualizeProcessor(),
            "Subtract": SubtractProcessor(),
            "Gamma": GammaProcessor(),
            "Smoothing": SmoothingProcessor(),
            "Morphology": MorphologyProcessor(),
            "CellCount": CellCountProcessor()
        }

    def _setup_window_geometry(self):
        """计算并设置窗口大小和位置（最大化）"""
        self.root.state('zoomed')

    def _load_image_file(self, file_path):
        """私有方法：统一图像加载入口"""
        try:
            image = Image.open(file_path)
            return image
        except Exception as e:
            self.ui.show_error(f"无法打开图像文件: {e}")
            return None

    def load_image(self):
        """加载图像文件并创建预览版本"""
        if self.is_closing:
            return
        file_path = open_image_file_dialog()
        if not file_path:
            return
        new_image = self._load_image_file(file_path)
        if new_image is None:
            return
        self.unload_image()  # 先卸载已有图像资源
        self.original_image = new_image
        self.current_image = self.original_image.copy()
        self.update_preview()
        self.ui.display_image(self.preview_image)
        self.ui.toggle_load_button(False)

    def update_preview(self):
        if self.current_image and not self.is_closing:
            width, height = self.current_image.size
            new_width = int((self.PREVIEW_HEIGHT / height) * width)
            self.preview_image = self.current_image.resize(
                (new_width, self.PREVIEW_HEIGHT),
                Image.Resampling.LANCZOS
            )

    def reload_image(self):
        """重新加载图像"""
        if self.is_closing:
            return
        self.unload_image()
        self.load_image()

    def unload_image(self):
        """卸载当前图像并释放资源"""
        if hasattr(self, 'original_image'):
            if self.original_image:
                self.original_image.close()
            if self.current_image:
                self.current_image.close()
            if self.preview_image:
                self.preview_image.close()
        self.original_image = None
        self.current_image = None
        self.preview_image = None
        if hasattr(self, 'ui') and not self.is_closing:
            self.ui.clear_image()
            self.ui.toggle_load_button(True)

    def process_image(self, processor_name):
        """处理图像（可叠加处理）"""
        if self.is_closing or not self.current_image:
            self.ui.show_warning("请先选择一张图片")
            return
        processor = self.processors[processor_name]
        parameters = processor.get_ui_parameters(self.ui)
        if parameters is None:
            return
        try:
            new_image = processor.process(self.current_image.copy(), **parameters)
            # 保存当前图像到历史栈
            self.image_history.append(self.current_image.copy())
            if len(self.image_history) > self.max_undo_steps:
                self.image_history.pop(0)
            if self.current_image:
                self.current_image.close()
            self.current_image = new_image
            self.update_preview()
            self.ui.display_image(self.preview_image)
        except Exception as e:
            self.ui.show_error(f"图像处理失败: {e}")

    def undo_last_action(self):
        """撤销上一次操作"""
        if not self.image_history:
            self.ui.show_info("没有更多可撤销的操作")
            return
        # 取出上一步图像
        previous_image = self.image_history.pop()
        if self.current_image:
            self.current_image.close()
        self.current_image = previous_image.copy()
        self.update_preview()
        self.ui.display_image(self.preview_image)

    def save_image(self):
        """保存最终处理后的图像"""
        if self.is_closing or not self.current_image:
            self.ui.show_warning("请先处理图像")
            return
        # 使用原始图像路径生成默认文件名
        file_path = save_image_file_dialog(original_path=self.original_image.filename if self.original_image else None)
        if file_path:
            try:
                self.current_image.save(file_path)
                self.ui.show_info("图像保存成功")
            except Exception as e:
                self.ui.show_error(f"保存图像失败: {e}")

    def on_close(self):
        """关闭窗口时的清理工作"""
        if self.is_closing:
            return
        self.is_closing = True
        # 清理图像资源
        self.unload_image()
        # 清理UI资源
        if hasattr(self, 'ui'):
            self.ui.cleanup()
        # 关闭窗口
        self.root.destroy()
        # 完全退出程序
        sys.exit(0)

if __name__ == "__main__":
    root = tk.Tk()
    app = ImageProcessorApp(root)
    root.mainloop()